home *** CD-ROM | disk | FTP | other *** search
- /* Low level AX.25 frame processing - address header */
-
- #include <stdio.h>
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "timer.h"
- #include "arp.h"
- #include "slip.h"
- #include "ax25.h"
- #include "lapb.h"
- #include <ctype.h>
-
- char axbdcst[AXALEN]; /* Broadcast address (QST-0), network format */
- int digipeat = 1; /* Controls single-band standard digipeating */
- struct mbuf *axloopq = NULLBUF; /* Loopback queue for AX.25 packets */
-
- /* Send IP datagrams across an AX.25 link */
- int
- ax_send(bp,interface,gateway,precedence,delay,throughput,reliability)
- struct mbuf *bp;
- struct interface *interface;
- int32 gateway;
- char precedence;
- char delay;
- char throughput;
- char reliability;
- {
- char *hw_addr,*res_arp();
- struct ax25_cb *axp,*find_ax25(),*open_ax25();
- struct ax25 addr;
- struct ax25_addr destaddr;
- struct mbuf *tbp;
- extern int16 axwindow;
- void ax_incom();
- int16 size,bsize,seq;
-
- if((hw_addr = res_arp(interface,ARP_AX25,gateway,bp)) == NULLCHAR)
- return 0; /* Wait for address resolution */
-
- if(delay || (!reliability && !(interface->flags & IF_CONNECT_MODE))){
- /* Use UI frame */
- return (*interface->output)(interface,hw_addr,
- interface->hwaddr,PID_FIRST|PID_LAST|PID_IP,bp);
- }
- /* Reliability is needed; use I-frames in AX.25 connection */
- memcpy(destaddr.call,hw_addr,ALEN);
- destaddr.ssid = hw_addr[ALEN];
-
- if((axp = find_ax25(&destaddr,(struct ax25_addr *)interface->hwaddr)) == NULLAX25 ||
- (axp->state != CONNECTED && axp->state != SETUP)){
- /* Open a new connection or reinitialize the old one */
- atohax25(&addr,hw_addr,(struct ax25_addr *)interface->hwaddr);
- axp = open_ax25(&addr,axwindow,ax_incom,NULLVFP,NULLVFP,interface,(char *)0);
- if(axp == NULLAX25){
- free_p(bp);
- return -1;
- }
- }
- /* If datagram is too big for one frame, send all but the last with
- * the extension PID. Note: the copy to a new buf is necessary because
- * AX.25 may continue retransmitting the frame after a local TCB has
- * gone away, and using the buf directly would cause heap garbage to be
- * transmitted. Besides, nobody would ever use AX.25 anywhere
- * high performance is needed anyway...
- */
- bsize = len_mbuf(bp);
- seq = 0;
- while(bsize != 0){
- size = min(bsize,axp->paclen);
- /* Allocate buffer, allowing space for PID */
- if((tbp = alloc_mbuf(size + 1)) == NULLBUF)
- break; /* out of memory! */
- *tbp->data = PID_IP;
- if(seq++ == 0)
- *tbp->data |= PID_FIRST; /* First in sequence */
- if(size == bsize)
- *tbp->data |= PID_LAST; /* That's all of it */
- /* else more to follow */
-
- tbp->cnt = 1;
- tbp->cnt += pullup(&bp,tbp->data + 1,size);
- send_ax25(axp,tbp);
- bsize -= size;
- }
- free_p(bp); /* Shouldn't be necessary */
- return 0;
- }
- /* Add AX.25 link header and send packet.
- * Note that the calling order here must match ec_output
- * since ARP also uses it.
- */
- ax_output(interface,dest,source,pid,data)
- struct interface *interface;
- char *dest; /* Destination AX.25 address (7 bytes, shifted) */
- /* Also includes digipeater string */
- char *source; /* Source AX.25 address (7 bytes, shifted) */
- char pid; /* Protocol ID */
- struct mbuf *data; /* Data field (follows PID) */
- {
- struct mbuf *abp,*cbp,*htonax25();
- struct ax25 addr;
-
- /* Allocate mbuf for control and PID fields, and fill in */
- if((cbp = pushdown(data,2)) == NULLBUF){
- free_p(data);
- return -1;
- }
- cbp->data[0] = UI;
- cbp->data[1] = pid;
-
- atohax25(&addr,dest,(struct ax25_addr *)source);
- if((abp = htonax25(&addr,cbp)) == NULLBUF){
- free_p(cbp); /* Also frees data */
- return -1;
- }
- /* This shouldn't be necessary because redirection has already been
- * done at the IP router layer, but just to be safe...
- */
- if(interface->forw != NULLIF)
- return (*interface->forw->raw)(interface->forw,abp);
- else
- return (*interface->raw)(interface,abp);
- }
- /* Process incoming AX.25 packets.
- * After optional tracing, the address field is examined. If it is
- * directed to us as a digipeater, repeat it. If it is addressed to
- * us or to QST-0 or NODES-0, kick it upstairs depending on the protocol ID.
- */
- int
- ax_recv(interface,bp)
- struct interface *interface;
- struct mbuf *bp;
- {
- void arp_input();
- int ip_route();
- struct ax25_addr addr,*ap;
- struct mbuf *htonax25(),*hbp;
- struct ax25 hdr;
- register struct ax25_cb *axp;
- struct ax25_cb *find_ax25(),*cr_ax25();
- register struct ax25_call *axc;
- struct ax25_call *axd;
- int timerscale,setdigi;
- extern int16 t1init,t2init,t3init,t4init;
-
- /* Pull header off packet and convert to host structure */
- if(ntohax25(&hdr,&bp) < 0){
- /* Something wrong with the header */
- free_p(bp);
- return;
- }
- /* Update the users liatifor persistence calculation */
- upd_nusers(interface,hdr.source.call);
- /* Update the MHEARD liatifor this interface */
- if(interface->mheard != 0){ /* first check if we have to keep it */
- updmheard(interface,1,&hdr); /* update the liat */
- }
- /* check source address. it must NOT appear in the exclude liat */
- ASSIGN(addr,hdr.source); /* get the source address */
- addr.ssid = 0; /* discard the SSID */
- if((axc = find_axcall(ax25_excl,&addr)) != NULLAXCALL &&
- ((axc->flags & MULTI_IF) || axc->interface == interface)) {
- free_p(bp);
- return;
- }
- timerscale = hdr.ndigis + 1; /* default scaling of timer values */
-
- /* Scan, looking for our call in the repeater fields, if any.
- * Repeat appropriate packets.
- */
- for(ap = &hdr.digis[0]; ap < &hdr.digis[hdr.ndigis]; ap++){
- if(ap->ssid & REPEATED)
- continue; /* Already repeated */
- /* Check if packet is directed to us as a digipeater */
- if((axc = find_axcall(ax25_digi,ap)) != NULLAXCALL){
- /* check dest address. it must NOT appear in the exclude liat */
- ASSIGN(addr,hdr.dest); /* get the dest address */
- addr.ssid = 0; /* discard the SSID */
- if((axd = find_axcall(ax25_excl,&addr)) != NULLAXCALL &&
- ((axd->flags & MULTI_IF) ||
- axd->interface == interface || axd->interface == axc->interface)) {
- free_p(bp);
- return; /* if any doubt, refuse it */
- }
- switch (axc->mode) /* check the digi mode */
- {
- case DIGIPEAT: /* bare digipeater */
- if (axc->interface == interface){ /* this band? */
- if (!digipeat) /* in-band digi disabled? */
- break; /* throw it away */
- } else { /* not "home", gateway request */
- if (axc->flags & DIGIGATEWAY &&
- (axd = find_axcall(ax25_digi,interface->hwaddr))
- != NULLAXCALL &&
- axd->mode == DIGIPEAT &&
- axd->flags & DIGIGATEWAY){
- /* swap callsign and interface */
- ASSIGN(*ap,*((struct ax25_addr *) interface->hwaddr));
- interface = axc->interface;
- } else {
- break; /* gateway conditions not fulfilled... */
- }
- }
-
- /* kick it back out */
- ap->ssid |= REPEATED;
- if((hbp = htonax25(&hdr,bp)) != NULLBUF){
- if(interface->forw != NULLIF)
- (*interface->forw->raw)(interface->forw,hbp);
- else
- (*interface->raw)(interface,hbp);
- tnc2_kissrcv(interface,&hdr,bp,4);
- bp = NULLBUF;
- }
- break;
-
- case DIGICONNECT: /* digipeater simulating connection */
- if ((axc->flags & MULTI_IF) ||
- axc->interface == interface ||
- (axc->flags & DIGIGATEWAY)){
- /* address is okay */
- if (bp != NULLBUF){
- timerscale = (int) (ap - &hdr.digis[0]) + 1;
- goto for_us;/* handle as if addressed to us */
- }
- }
- break;
- }
- }
- tnc2_kissrcv(interface,&hdr,bp,4);
- free_p(bp); /* Dispose if not forwarded */
- return;
- }
- /* Packet has passed all repeaters, now look at destination */
- if((axc = find_axcall(ax25_call,&hdr.dest)) == NULLAXCALL ||
- !((axc->flags & MULTI_IF) || axc->interface == interface)) {
- /* Not for us, or wrong interface for this callsign */
- tnc2_kissrcv(interface,&hdr,bp,3);
- free_p(bp);
- return;
- }
-
- if(bp == NULLBUF){
- /* Nothing left */
- return;
- }
- /* Sneak a peek at the control field. This kludge is necessary because
- * AX.25 lacks a proper protocol ID field between the address and LAPB
- * sublayers; a control value of UI indicates that LAPB is to be
- * bypassed.
- */
- if((*bp->data & ~PF) == UI && axc->mode == IP_ARP_CON){
- char pid;
-
- tnc2_kissrcv(interface,&hdr,bp,2);
- (void) pullchar(&bp);
- if(pullup(&bp,&pid,1) != 1)
- return; /* No PID */
- /* Handle packets. Multi-frame messages are not allowed */
- switch(pid & (PID_FIRST | PID_LAST | PID_PID))
- {
- case (PID_IP | PID_FIRST | PID_LAST):
- if(!(axc->flags & MULTICAST) || axc->flags & IP_ARP_MULTI){
- ip_route(bp,axc->flags & MULTICAST);
- return;
- }
- case (PID_ARP | PID_FIRST | PID_LAST):
- if(!(axc->flags & MULTICAST) || axc->flags & IP_ARP_MULTI){
- arp_input(interface,bp);
- return;
- }
- case (PID_NETROM | PID_FIRST | PID_LAST):
- /* NET/ROM is very poorly layered. The meaning of the stuff
- * following the PID of CF depends on what's in the AX.25 dest
- * field.
- */
- if(axc->flags & NETROM_MULTI && hdr.ndigis == 0){
- nr_nodercv(interface,&hdr.source,bp);
- return;
- }
- break;
- }
- free_p(bp);
- return;
- }
-
- if(axc->flags & MULTICAST){ /* don't allow connects to broadcast */
- tnc2_kissrcv(interface,&hdr,bp,2);
- free_p(bp);
- return;
- }
-
- for_us: if (axc->port == TNC2PORT &&
- (axc->mode == CONNECT || axc->mode == DIGICONNECT) &&
- tnc2_kissrcv(interface,&hdr,bp,1)) {
- free_p(bp);
- return;
- }
-
- tnc2_kissrcv(interface,&hdr,bp,2);
-
- setdigi = 0; /* no need to set digi path (yet) */
- /* Find the source/dest address pair in hash table */
- if((axp = find_ax25(&hdr.source,&hdr.dest)) == NULLAX25){
- /* He is new! First check for reasonable callsign */
- if(valid_addr(&hdr.source) != 0) {
- free_p(bp);
- return;
- }
- /* Create a new ax25 entry for this guy,
- * insert into hash table keyed on his address,
- * and initialize table entries
- */
- if((axp = cr_ax25(&hdr.source,&hdr.dest)) == NULLAX25){
- free_p(bp);
- return;
- }
- /* Swap source and destination callsigns */
- ASSIGN(axp->addr.dest,hdr.source);
- ASSIGN(axp->addr.source,hdr.dest);
- setdigi++; /* also set the digi string and interface */
-
- /* see if it is a connection to an ax25 port */
- if (axc->port != 0 && /* a port ? */
- (axc->mode == CONNECT || axc->mode == DIGICONNECT)){
- axp->r_upcall = axc->r_upcall; /* set upcall handlers */
- axp->t_upcall = axc->t_upcall;
- axp->s_upcall = axc->s_upcall;
- axp->user = (char *) axc; /* link to ax call */
- }
- }
-
- /* set digi path for new connections, but always set it when the
- * received frame is an SABM. This allows other stations to
- * reconnect to us with a different digi path (TNC2 reconnect cmd).
- * same holds for the interface the connection is on.
- */
- if(setdigi || ((*bp->data & ~PF) == SABM)){
- if(hdr.ndigis > 0){
- int i,j;
-
- /* Construct reverse digipeater path */
- for(i=hdr.ndigis-1,j=0;i >= 0;i--,j++){
- ASSIGN(axp->addr.digis[j],hdr.digis[i]);
- axp->addr.digis[j].ssid ^= REPEATED;
- axp->addr.digis[j].ssid &= ~E;
- }
- }
- /* Scale timers to account for extra delay */
- axp->t1.start = t1init * timerscale;
- axp->t2.start = t2init * timerscale;
- /*axp->t3.start = t3init * timerscale;
- axp->t4.start = t4init * timerscale;*/
- axp->addr.ndigis = hdr.ndigis;
-
- axp->interface = interface;
- }
-
- if(hdr.cmdrsp == UNKNOWN)
- axp->proto = V1; /* Old protocol in use */
- else
- axp->proto = V2;
-
- lapb_input(axp,hdr.cmdrsp,bp);
- }
-
- /* General purpose AX.25 frame output */
- int
- sendframe(axp,cmdrsp,ctl,data)
- struct ax25_cb *axp;
- char cmdrsp;
- char ctl;
- struct mbuf *data;
- {
- struct mbuf *hbp,*cbp,*ibp,*htonax25();
- struct ax25_call *axc;
- int rv,i;
-
- if(axp == NULLAX25 || axp->interface == NULLIF)
- return -1;
-
- /* Add control field */
- if((cbp = pushdown(data,1)) == NULLBUF){
- free_p(data);
- return -1;
- }
- cbp->data[0] = ctl;
-
- axp->addr.cmdrsp = cmdrsp;
- /* Create address header */
- if((hbp = htonax25(&axp->addr,cbp)) == NULLBUF){
- free_p(cbp);
- return -1;
- }
-
- /* First make a check to see if it's directed to ourselves */
- for(i = 0; i < axp->addr.ndigis; i++)
- if(!(axp->addr.digis[i].ssid & REPEATED))
- break;
- if((i == axp->addr.ndigis &&
- (axc = find_axcall(ax25_call,&axp->addr.dest)) != NULLAXCALL) ||
- (i < axp->addr.ndigis &&
- (axc = find_axcall(ax25_digi,&axp->addr.digis[i])) != NULLAXCALL) &&
- !(axc->flags & MULTICAST) &&
- ((axc->flags & (MULTI_IF|DIGIGATEWAY)) || axc->interface == axp->interface)) {
- /* put it on the ax loopback queue with interface ptr */
- if((ibp = alloc_mbuf(4 + len_mbuf(hbp))) == NULLBUF){
- free_p(hbp);
- return -1;
- }
- put32(ibp->data,(long) axp->interface);
- ibp->cnt = 4 + pullup(&hbp,ibp->data + 4,len_mbuf(hbp));
- enqueue(&axloopq,ibp);
- rv = 0;
- } else {
- /* Not for us, really ship it */
- if(axp->interface->forw != NULLIF)
- rv = (*axp->interface->forw->raw)(axp->interface->forw,hbp);
- else
- rv = (*axp->interface->raw)(axp->interface,hbp);
- }
-
- if(cmdrsp == COMMAND)
- start_timer(&axp->t1);
-
- return rv;
- }
- /* AX.25 UI frame output for beacons etc */
- int
- senduiframe(ifp,addr,data)
- struct interface *ifp;
- struct ax25 *addr;
- struct mbuf *data;
- {
- struct mbuf *hbp,*cbp,*htonax25();
-
- if(ifp == NULLIF)
- return -1;
-
- /* Add control field (UI) */
- if((cbp = pushdown(data,1)) == NULLBUF){
- free_p(data);
- return -1;
- }
- cbp->data[0] = UI;
-
- addr->cmdrsp = UNKNOWN;
- /* Create address header */
- if((hbp = htonax25(addr,cbp)) == NULLBUF){
- free_p(cbp);
- return -1;
- }
-
- /* Ship it */
- if(ifp->forw != NULLIF)
- return (*ifp->forw->raw)(ifp->forw,hbp);
- else
- return (*ifp->raw)(ifp,hbp);
- }
- /* Initialize AX.25 entry in arp device table. also puts it in call table */
- axarp()
- {
- int psax25(),setpath();
- struct ax25_call *axc;
- struct ax25_addr ax25_bdcst;
-
- setcall(&ax25_bdcst,"QST-0");
- if ((axc = cr_axcall(ax25_call,&ax25_bdcst)) != NULLAXCALL){
- axc->mode = IP_ARP_CON;
- axc->flags = MULTI_IF | MULTICAST | IP_ARP_MULTI;
- }
-
- memcpy(axbdcst,ax25_bdcst.call,ALEN);
- axbdcst[ALEN] = ax25_bdcst.ssid;
-
- arp_init(ARP_AX25,AXALEN,PID_FIRST|PID_LAST|PID_IP,
- PID_FIRST|PID_LAST|PID_ARP,axbdcst,psax25,setpath);
- }
-